//
//  graphics.cpp
//  RPG
//
//  Created by Matt Bailey on 29/12/2013.
//  Copyright (c) 2013 Matt Bailey. All rights reserved.
//

#include "graphics.hpp"

string vertexPath, fragmentPath;

void Graphics::init() {
    
    parseConfig();
    
    initGLFW();
    Game::setWindow() = Window::createWindow();
    glfwMakeContextCurrent(Game::getWindow());
    
    initGLEW();
    createVAO();
    
    shader.init(vertexPath, fragmentPath);
    
    glfwSetScrollCallback(Game::getWindow(), Window::scrollCallback);
    glfwSwapInterval(Window::getVsync());
    
    glUseProgram(Graphics::shader.getProgramID());
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

GLuint Graphics::createVAO() {
    
    glGenVertexArrays(1, &vertexArrayID);
    glBindVertexArray(vertexArrayID);
    
    return vertexArrayID;
}

GLuint Graphics::loadPNG(string fileName) {
    
    std::vector<unsigned char> image;
    unsigned imageWidth, imageHeight;
    
    // Load and Decode PNG with *sigh* 'LodePNG' (insert Oxford dictionary)
    unsigned error = lodepng::decode(image, imageWidth, imageHeight, fileName);
    
    if(error != 0)
    {
        cout << "\nERROR: Cannot Load Texture: " << fileName << "\n";
        cout << lodepng_error_text(error);
        return 1;
    }
    
    // Make a new Texture
    GLuint textureID;
    glGenTextures(1, &textureID);
    glBindTexture(GL_TEXTURE_2D, textureID);
    
    glPixelStorei(GL_UNPACK_ALIGNMENT,1);
    
    // Set Filtering and Enable Texture
    glEnable(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &image[0]);
    
    return textureID;
}

void Graphics::render(GLuint vertexBuffer, GLenum mode, unsigned int size, unsigned int location) {

    glEnableVertexAttribArray(location);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, 0, (void*)0);

    glDrawArrays(GL_TRIANGLES, 0, size);
    glDisableVertexAttribArray(location);
}

GLuint Graphics::createVBO(const vector<glm::vec2> vertexData) {
    
    GLuint vertexBuffer;
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    
    glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(glm::vec2), &vertexData.front(), GL_STATIC_DRAW);
    
    return vertexBuffer;
}

void Graphics::initGLFW() {
    
    if (!glfwInit()) {
        cout << "ERROR: GLFW failed to Initialise" << endl;
        exit(EXIT_FAILURE);
    }
}

void Graphics::initGLEW() {
    
    glewExperimental = GL_TRUE;
    
    if (glewInit() != GLEW_OK) {
        cout << "ERROR: GLEW failed to Initialise" << endl;
        exit(EXIT_FAILURE);
    }
    
    glEnable(GLFW_STICKY_KEYS);
}

void Graphics::parseConfig() {
    
    stringstream ss;
    string line;
    
    ss.str("");
    ss << settings;
    
    while (getline(ss, line)) {
        
        stringstream ls(line);
        string variableName; string value;
        
        ls >> variableName >> value;
        
        if (variableName == "vertexPath") {
            vertexPath = value;
        }
        
        if (variableName == "fragmentPath") {
            fragmentPath = value;
        }
    }
}

string Graphics::settings;
        
GLuint Graphics::vertexArrayID;
Shader Graphics::shader;
